//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
// 
// File: remoting.h
// 

// 
// Purpose: Defines various remoting related objects such as
//          proxies
//

// 


#ifndef __REMOTING_H__
#define __REMOTING_H__

#ifndef FEATURE_REMOTING
#error FEATURE_REMOTING is not set, please do not include remoting.h
#endif

#include "fcall.h"
#include "stubmgr.h"

// Forward declaration
class TPMethodFrame;

// <TODO>@TODO: Set the hashtable to delete the data.</TODO>

// Thunk hash table - the keys are MethodDesc
typedef EEHashTable<MethodDesc *, EEPtrHashTableHelper<MethodDesc *>, FALSE> EEThunkHashTable;

// ConstVirtualThunkSize declares the size of the code generated by
// CTPMethodTable::CreateThunkForVirtualMethod
#ifdef _TARGET_X86_

static const DWORD ConstVirtualThunkSize    = sizeof(BYTE) + sizeof(DWORD) + sizeof(BYTE) + sizeof(LONG);

#elif defined(_TARGET_AMD64_)

static const DWORD ConstVirtualThunkSize    = sizeof(DWORD) + sizeof(UINT64) + 7;

#elif defined(_TARGET_ARM_)

static const DWORD ConstVirtualThunkSize    = 12;

#else
PORTABILITY_WARNING("Remoting thunk size not defined for this platform.")
static const DWORD ConstVirtualThunkSize    = sizeof(LPVOID);
#endif

extern "C"
{
    UINT_PTR __stdcall CRemotingServices__CheckForContextMatch(Object* pStubData);
    void __stdcall CRemotingServices__DispatchInterfaceCall();
    void __stdcall CRemotingServices__CallFieldGetter(MethodDesc *pMD, LPVOID pThis, LPVOID pFirst, LPVOID pSecond, LPVOID pThird);
    void __stdcall CRemotingServices__CallFieldSetter(MethodDesc *pMD, LPVOID pThis, LPVOID pFirst, LPVOID pSecond, LPVOID pThird);
}

extern "C" LPVOID __stdcall CTPMethodTable__CallTargetHelper2(const void *pTarget, LPVOID pvFirst, LPVOID pvSecond);
extern "C" LPVOID __stdcall CTPMethodTable__CallTargetHelper3(const void *pTarget, LPVOID pvFirst, LPVOID pvSecond, LPVOID pvThird);
extern "C" BOOL __stdcall CTPMethodTable__GenericCheckForContextMatch(Object* orTP);


// These are the values returned by RequiresManagedActivation
enum ManagedActivationType
{
    NoManagedActivation = 0,
    ManagedActivation   = 0x1,
#ifdef FEATURE_COMINTEROP
    ComObjectType       = 0x2,
#endif // FEATURE_COMINTEROP
};


struct timingData
{
    DWORD       threadId;
    BYTE        stage;
    __int64     cycleCount;
};


// This struct is also accessed from managed world
struct messageData
{
    PVOID       pFrame;
    MethodDesc  *pMethodDesc;
    MethodDesc  *pDelegateMD;
    MetaSig     *pSig;
    TypeHandle  thGoverningType;
    INT32       iFlags;
};


// The real proxy class is the class behind the 
// transparent proxy class
class CRealProxy
{
public:
    // Native helpers
    static FCDECL2(VOID, SetStubData, Object* orRPUNSAFE, Object* orStubDataUNSAFE);
    static FCDECL1(Object*, GetStubData, Object* orRPUNSAFE);
    static FCDECL1(LPVOID, GetStub, Object* orRPUNSAFE);
    static FCDECL0(LPVOID, GetDefaultStub);
    static FCDECL1(Object*, GetProxiedType, Object* orRPUNSAFE);
    
    static VOID UpdateOptFlags(OBJECTREF refTP);
    static BOOL ProxyTypeIdentityCheck(MethodTable *pCliHierarchy, MethodTable *pSrvHierarchy);
};

// Forward declarations
class CVirtualThunkMgr;
class CNonVirtualThunkMgr;




// Class that provides various remoting services
// to the exposed world
class CRemotingServices
{
private:
    //+-------------------------------------------------------------------
    //
    //  Struct:     FieldArgs
    //
    //  Synopsis:   Structure to GC protect arguments for a field accessor call.
    //              DO NOT add non OBJECTREF data types in the structure
    //              see GCPROTECT_BEGIN() for a better explanation.
    //
    //+-------------------------------------------------------------------
    typedef struct _FieldArgs
    {
        OBJECTREF obj;
        OBJECTREF val;
        STRINGREF typeName;
        STRINGREF fieldName;        
    } FieldArgs;

public:
    
    // Methods related to interception of non virtual methods & virtual methods called
    // non virtually
    static PCODE    GetNonVirtualEntryPointForVirtualMethod(MethodDesc* pMD);
    
#ifndef HAS_REMOTING_PRECODE
    static Stub*    GetStubForNonVirtualMethod(MethodDesc* pMD, LPVOID pvAddrOfCode, Stub* pInnerStub);
#endif

    static void     DestroyThunk(MethodDesc* pMD);
    
    // Methods related to interception of interface calls
    static PCODE    GetDispatchInterfaceHelper(MethodDesc* pMD);

    static OBJECTREF    CreateProxyOrObject(MethodTable *pMT, BOOL fIsCom = FALSE, BOOL fIsNewObj = FALSE);
    
    // Methods related to field accessors
    static void FieldAccessor(FieldDesc* pFD, OBJECTREF o, LPVOID pVal, BOOL fIsGetter);
    
    // Methods related to wrapping/unwrapping of objects
    static OBJECTREF WrapHelper(OBJECTREF obj);
    
    static OBJECTREF Wrap(OBJECTREF obj);
    static OBJECTREF GetProxyFromObject(OBJECTREF obj);
    static OBJECTREF GetObjectFromProxy(OBJECTREF obj);
    static BOOL IsProxyToRemoteObject(OBJECTREF obj);
    static OBJECTREF GetServerContext(OBJECTREF obj);
    
    // Methods related to creation and marshaling of appdomains
    static OBJECTREF CreateProxyForDomain(AppDomain *pDomain);

    // Extract the true class of a proxy
    static REFLECTCLASSBASEREF GetClass(OBJECTREF pThis);

    // Initialization function.
    static VOID Initialize();

    // Start up function. This actually starts up the remoting services.
    static void EnsureRemotingStarted();

    // Other helper functions.
    inline static MethodDesc *MDofPrivateInvoke()
    {
        CONTRACT (MethodDesc*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL));
        }
        CONTRACT_END;
        
        RETURN s_pRPPrivateInvoke;
    }
    
    inline static MethodDesc *MDofInvokeStatic()
    {
        CONTRACT (MethodDesc*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL));
        }
        CONTRACT_END;
        
        RETURN s_pRPInvokeStatic;
    }
    
    inline static MethodDesc *MDofIsCurrentContextOK()
    {
        CONTRACT (MethodDesc*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL));
        }
        CONTRACT_END;
        
        RETURN s_pIsCurrentContextOK;
    }
    
    inline static MethodDesc *MDofCheckCast()
    {
        CONTRACT (MethodDesc*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL));
        }
        CONTRACT_END;
        
        RETURN s_pCheckCast;
    }
    
    inline static MethodDesc *MDofWrap()
    {
        CONTRACT (MethodDesc*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL));
        }
        CONTRACT_END;
        
        RETURN s_pWrapMethodDesc;
    }
    
    inline static MethodDesc *MDofFieldSetter()
    {
        CONTRACT (MethodDesc*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL));
        }
        CONTRACT_END;
        
        RETURN s_pFieldSetterDesc;
    }
    
    inline static MethodDesc *MDofFieldGetter()
    {
        CONTRACT (MethodDesc*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL));
        }
        CONTRACT_END;
        
        RETURN s_pFieldGetterDesc;
    }
    
    inline static MethodDesc *MDofGetType()
    {
        CONTRACT (MethodDesc*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL));
        }
        CONTRACT_END;
        
        RETURN s_pGetTypeDesc;
    }

    inline static MethodDesc *MDofObjectGetType()
    {
        CONTRACT (MethodDesc*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL));
        }
        CONTRACT_END;
        
        RETURN s_pObjectGetTypeDesc; 
    }

#ifdef FEATURE_COMINTEROP
    inline static MethodDesc *MDofCreateObjectForCom()
    {
        CONTRACT (MethodDesc*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL));
        }
        CONTRACT_END;
        
        RETURN s_pCreateObjectForCom;
    }

   
    static BOOL CallSupportsInterface(OBJECTREF realProxy, REFIID iid, ARG_SLOT *pret);
    
    // helpers to call methods in real proxy
    static VOID CallSetDCOMProxy(OBJECTREF realProxy, IUnknown* pUnk);

#endif // FEATURE_COMINTEROP

    inline static BOOL IsInstanceOfServerIdentity(MethodTable* pMT)
    {
        CONTRACTL
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            PRECONDITION(CheckPointer(pMT));
        }
        CONTRACTL_END;
        
        return s_pServerIdentityClass == pMT;
    }

    inline static MethodTable *GetMarshalByRefClass()
    {
        CONTRACT (MethodTable*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL));
        }
        CONTRACT_END;
        
        RETURN s_pMarshalByRefObjectClass;
    }

    static INT32 IsTransparentProxy(Object* obj);
    static Object* GetRealProxy(Object* obj);

    static BOOL CheckCast(OBJECTREF orTP, TypeHandle ty);
    static BOOL CheckCast(OBJECTREF orTP, TypeHandle objTy, TypeHandle ty);
    static OBJECTREF GetExposedContext();
    static AppDomain *GetServerDomainForProxy(OBJECTREF orTP);
    static Context *GetServerContextForProxy(OBJECTREF orTP);
    static int GetServerDomainIdForProxy(OBJECTREF orTP);
    static UINT_PTR CheckForContextMatch(Object* pStubData);

    static ManagedActivationType __stdcall RequiresManagedActivation(TypeHandle ty);        
    static BOOL IsRemotingStarted()
    {
        LIMITED_METHOD_CONTRACT;
        return s_fRemotingStarted;
    };
    
    static DWORD GetOffsetOfSrvIdentityInRP() { return s_dwSrvIdentityOffsetInRealProxy; }
    static DWORD GetOffsetOfCliIdentityInRP() { return s_dwIdOffset; }
    static DWORD GetOffsetOfTPOrObjInIdentity() { return s_dwTPOrObjOffsetInIdentity; }
    static DWORD GetOffsetOfLeaseInIdentity() { return s_dwLeaseOffsetInIdentity; }
    static DWORD GetOffsetOfURIInIdentity() { return s_dwURIOffsetInIdentity; }
    inline static MethodDesc *MDofRenewLeaseOnCall() {  return s_pRenewLeaseOnCallDesc; }

    static PCODE GetStubForInterfaceMethod(MethodDesc *pItfMD);
private:
    static void StartRemoting();
    static void CopyDestToSrc(LPVOID pDest, LPVOID pSrc, UINT cbSize);
    static void CallFieldAccessor(FieldDesc* pFD, OBJECTREF o, VOID * pVal,
                                  BOOL fIsGetter, BOOL fIsByValue, BOOL fIsGCRef,
                                  TypeHandle ty, TypeHandle fldTy,
                                  CorElementType fieldType, UINT cbSize);

    static void GetTypeAndFieldName(FieldArgs *pArgs, FieldDesc *pFD, TypeHandle thEnclosingClass);
    static BOOL MatchField(FieldDesc* pCurField, LPCUTF8 szFieldName);
    static OBJECTREF SetExposedContext(OBJECTREF newContext);
    static OBJECTREF GetServerIdentityFromProxy(OBJECTREF obj);
    inline static MethodDesc *MDOfCreateProxyForDomain()
    {
        CONTRACT (MethodDesc*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL));
        }
        CONTRACT_END;
        
        RETURN s_pProxyForDomainDesc;
    }
    
    inline static MethodDesc *MDofGetServerContextForProxy()
    {
        CONTRACT (MethodDesc*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL));
        }
        CONTRACT_END;
        
        RETURN s_pServerContextForProxyDesc;
    }
    
    inline static MethodDesc *MDofGetServerDomainIdForProxy()
    {
        CONTRACT (MethodDesc*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL));
        }
        CONTRACT_END;
        
        RETURN s_pServerDomainIdForProxyDesc;
    }
    
    static VOID InitActivationServicesClass();
    static VOID InitRealProxyClass();
    static VOID InitRemotingProxyClass();
    static VOID InitServerIdentityClass();
    static VOID InitIdentityClass();
    static VOID InitMarshalByRefObjectClass();
    static VOID InitRemotingServicesClass();
    static VOID InitObjectClass();
    static VOID InitLeaseClass();

    static MethodTable *s_pMarshalByRefObjectClass;    
    static MethodTable *CRemotingServices::s_pServerIdentityClass;
    static MethodTable *CRemotingServices::s_pContextClass;

    static MethodDesc *s_pRPPrivateInvoke;
    static MethodDesc *s_pRPInvokeStatic;
    static MethodDesc *s_pIsCurrentContextOK;
    static MethodDesc *s_pCheckCast;
    static MethodDesc *s_pWrapMethodDesc;    
    static MethodDesc *s_pFieldSetterDesc;
    static MethodDesc *s_pFieldGetterDesc;
    static MethodDesc *s_pObjectGetTypeDesc;
    static MethodDesc *s_pGetTypeDesc;
    static MethodDesc *s_pProxyForDomainDesc;
    static MethodDesc *s_pServerContextForProxyDesc;
    static MethodDesc *s_pServerDomainIdForProxyDesc;
    static MethodDesc *s_pRenewLeaseOnCallDesc;
    static DWORD s_dwIdOffset;    
    static DWORD s_dwServerOffsetInRealProxy;
    static DWORD s_dwSrvIdentityOffsetInRealProxy;
    static DWORD s_dwTPOrObjOffsetInIdentity;
    static DWORD s_dwLeaseOffsetInIdentity;
    static DWORD s_dwURIOffsetInIdentity;
    static DWORD s_dwMBRIDOffset;
    static CrstStatic s_RemotingCrst;
    static BOOL s_fRemotingStarted;
    
#ifdef FEATURE_COMINTEROP
    static MethodDesc *s_pCreateObjectForCom;
#endif // FEATURE_COMINTEROP
    
};

// Class that manages transparent proxy thunks
class CVirtualThunks
{
public:
    inline static CVirtualThunks* GetVirtualThunks()
    {
        CONTRACT (CVirtualThunks*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
            SO_TOLERANT;
        }
        CONTRACT_END;
        
        RETURN s_pVirtualThunks;
    }
    
    inline static CVirtualThunks* SetVirtualThunks(CVirtualThunks* pThunks) 
    {
        CONTRACT (CVirtualThunks*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            PRECONDITION(CheckPointer(pThunks));
            POSTCONDITION(CheckPointer(RETVAL));
        }
        CONTRACT_END;
        
        RETURN (s_pVirtualThunks = pThunks);
    }

    inline CVirtualThunks* GetNextThunk()
    {
        CONTRACT (CVirtualThunks*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
            SO_TOLERANT;
        }
        CONTRACT_END;
        
        RETURN _pNext;
    }

    // Public member variables
    CVirtualThunks *_pNext;
    DWORD _dwReservedThunks;
    DWORD _dwStartThunk;
    DWORD _dwCurrentThunk;
    
#ifdef CVIRTUALTHUNKS_ALIGNPAD_BYTES
    BYTE    pad[CVIRTUALTHUNKS_ALIGNPAD_BYTES];
#endif

    struct tagThunkCode
    {
        BYTE pCode[ConstVirtualThunkSize];
    } ThunkCode[1];

private:
    // Cannot be created
    CVirtualThunks(CVirtualThunks *pNext, DWORD dwCommitedSlots, DWORD dwReservedSlots, DWORD dwStartSlot, DWORD dwCurrentSlot)
    {
        LIMITED_METHOD_CONTRACT;
    }

    // Private statics
    static CVirtualThunks *s_pVirtualThunks;
};


#ifndef HAS_REMOTING_PRECODE

class CNonVirtualThunk
{
public: 
    // Constructor
    CNonVirtualThunk(const BYTE* pbCode)
    : _addrOfCode(pbCode), _pNext(NULL)
    {
        WRAPPER_NO_CONTRACT;
    }
    
    ~CNonVirtualThunk();
    
    inline LPVOID*  GetAddrOfCode()
    {
        CONTRACT (LPVOID*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL));
        }
        CONTRACT_END;
        
        RETURN (LPVOID*)&_addrOfCode;
    }

    inline const BYTE* GetThunkCode()
    {
        CONTRACT (const BYTE*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL));
            SO_TOLERANT;
        }
        CONTRACT_END;
        
        RETURN _addrOfCode;
    }
    
    inline CNonVirtualThunk* GetNextThunk()
    {
        CONTRACT (CNonVirtualThunk*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
            SO_TOLERANT;
        }
        CONTRACT_END;
        
        RETURN _pNext;
    }
    
    static void InitializeListLock();
    static CNonVirtualThunk* AddrToThunk(LPVOID pAddr);
    inline static CNonVirtualThunk* GetNonVirtualThunks()
    {
        CONTRACT (CNonVirtualThunk*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
            SO_TOLERANT;
        }
        CONTRACT_END;
        
        RETURN s_pNonVirtualThunks;
    }

    inline static SimpleRWLock* GetThunksListLock()
    {
        LIMITED_METHOD_CONTRACT;

        return s_pNonVirtualThunksListLock;
    }
    
    static CNonVirtualThunk* SetNonVirtualThunks(const BYTE* pbCode); 

    const BYTE* _addrOfCode;
    
private:    

    void SetNextThunk();

    // Private statics
    static CNonVirtualThunk *s_pNonVirtualThunks;

    // reader/writer lock to be taken when manipulating s_pNonVirtualThunks
    static SimpleRWLock* s_pNonVirtualThunksListLock;

    // Private members
    CNonVirtualThunk* _pNext;
};

inline void CNonVirtualThunk::InitializeListLock() 
{ 
    CONTRACTL
    {
        THROWS;
        GC_NOTRIGGER;
        MODE_ANY;
    }
    CONTRACTL_END;

    if (s_pNonVirtualThunksListLock == NULL)
        s_pNonVirtualThunksListLock = new SimpleRWLock(COOPERATIVE_OR_PREEMPTIVE, LOCK_TYPE_DEFAULT);
}

inline void CNonVirtualThunk::SetNextThunk()  
{
    LIMITED_METHOD_CONTRACT;

    SimpleRWLock::SimpleWriteLockHolder swlh(s_pNonVirtualThunksListLock);

    _pNext = s_pNonVirtualThunks; 
    s_pNonVirtualThunks = this;
}

inline CNonVirtualThunk* CNonVirtualThunk::AddrToThunk(LPVOID pAddr)
{
    CONTRACT (CNonVirtualThunk*)
    {
        NOTHROW;
        GC_NOTRIGGER;
        MODE_ANY;
        PRECONDITION(CheckPointer(pAddr));
        POSTCONDITION(CheckPointer(RETVAL));
    }
    CONTRACT_END;
    
    RETURN (CNonVirtualThunk *)((size_t)pAddr - (size_t)offsetof(CNonVirtualThunk, _addrOfCode));
}

#endif // HAS_REMOTING_PRECODE


class CTPMethodTable
{
    friend class CRemotingServices;
    friend class RemotingNative;
    
public:
    // Public statics    
    static DWORD GetCommitedTPSlots()
    {
        LIMITED_METHOD_CONTRACT;
        return s_dwCommitedTPSlots;
    }
        
    static MethodTable *GetMethodTable()
    {
        CONTRACT (MethodTable*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            POSTCONDITION(CheckPointer(RETVAL));
            SO_TOLERANT;
        }
        CONTRACT_END;
        
        RETURN s_pThunkTable;
    }
    
    static VOID Initialize();
    
#ifndef HAS_REMOTING_PRECODE
    static PTR_PCODE GetOrCreateNonVirtualSlotForVirtualMethod(MethodDesc* pMD);
    static PCODE CreateNonVirtualThunkForVirtualMethod(MethodDesc* pMD);
    static Stub* CreateStubForNonVirtualMethod(MethodDesc* pMD, CPUSTUBLINKER *psl, LPVOID pvAddrOfCode, Stub* pInnerStub);
#endif // HAS_REMOTING_PRECODE

    static REALPROXYREF GetRP(OBJECTREF orTP);
    static MethodTable * GetMethodTableBeingProxied(OBJECTREF orTP);

    static LPVOID __stdcall CallTarget(MethodDesc* pTargetMD, LPVOID pvFirst, LPVOID pvSecond);
    static LPVOID __stdcall CallTarget(MethodDesc* pTargetMD, LPVOID pvFirst, LPVOID pvSecond, LPVOID pvThird);
    static BOOL CheckCastHelper(MethodDesc* pTargetMD, LPVOID pvFirst, LPVOID pvSecond);
    static BOOL CheckCast(MethodDesc* pTargetMD, TRANSPARENTPROXYREF orTP, TypeHandle ty);
    static void RefineProxy(TRANSPARENTPROXYREF orTP, TypeHandle ty);
    
    static PCODE GetTPStubEntryPoint();
    static PCODE GetDelegateStubEntryPoint();

    static void DestroyThunk(MethodDesc* pMD);

    // Interpretation of __TransparentProxy._stub
    typedef UINT_PTR CheckContextCrossingProc (Object*);

    inline static BOOL IsInstanceOfRemotingProxy(MethodTable *pMT) 
    {
        CONTRACTL
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            PRECONDITION(CheckPointer(pMT));
        }
        CONTRACTL_END;
        
        return s_pRemotingProxyClass == pMT;
    }

private:

#ifndef DACCESS_COMPILE

    // Private statics    
    static void InitThunkTable(DWORD dwCommitedTPSlots, DWORD dwReservedTPSlots, MethodTable* pTPMethodTable)
    {
        CONTRACTL
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            PRECONDITION(CheckPointer(pTPMethodTable));
        }
        CONTRACTL_END;
        
        s_dwCommitedTPSlots = dwCommitedTPSlots;
        s_dwReservedTPSlots = dwReservedTPSlots;
        s_pThunkTable = pTPMethodTable;    
    }

    
    static void DestroyThunkTable()
    {
        WRAPPER_NO_CONTRACT;
        ::ClrVirtualFree(MTToAlloc(s_pThunkTable, s_dwGCInfoBytes), 0, MEM_RELEASE);
        s_pThunkTable = NULL;
        s_dwCommitedTPSlots = 0;
        s_dwReservedTPSlots = 0;
    }

#endif // #ifndef DACCESS_COMPILE
    
    static void EnsureFieldsInitialized();

    static void CreateTPOfClassForRP(TypeHandle ty, REALPROXYREF *pRP, TRANSPARENTPROXYREF *pTP);
    static void CreateTPMethodTable(MethodTable* pTPMT);
    static BOOL ExtendCommitedSlots(_In_range_(1,64*1024) DWORD dwSlots);
    static BOOL AllocateThunks(DWORD dwSlots, DWORD dwCommitSize);
#ifdef HAS_REMOTING_PRECODE
    static void ActivatePrecodeRemotingThunk();
#endif // HAS_REMOTING_PRECODE
    static MethodTable *AllocToMT(BYTE *Alloc, LONG off)
    {
        CONTRACT (MethodTable*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            PRECONDITION(CheckPointer(Alloc));
            POSTCONDITION(CheckPointer(RETVAL));
        }
        CONTRACT_END;
        
        RETURN (MethodTable *) (Alloc + off);
    }
    
    static BYTE *MTToAlloc(MethodTable *MT, LONG off)
    {
        CONTRACT (BYTE*)
        {
            NOTHROW;
            GC_NOTRIGGER;
            MODE_ANY;
            PRECONDITION(CheckPointer(MT));
            POSTCONDITION(CheckPointer(RETVAL));
        }
        CONTRACT_END;
        
        RETURN (((BYTE *) MT) - off);
    }
    
    static PCODE CreateThunkForVirtualMethod(DWORD dwSlot, BYTE *bCode);    
    
    // Static members    
    static DWORD s_dwCommitedTPSlots;
    static DWORD s_dwReservedTPSlots;
    static DWORD s_dwReservedTPIndirectionSlotSize;
    SPTR_DECL(MethodTable, s_pThunkTable);
    static MethodTable* s_pRemotingProxyClass;
    static DWORD s_dwGCInfoBytes;
    static DWORD s_dwMTDataSlots;
    static CrstStatic s_TPMethodTableCrst;
    static EEThunkHashTable *s_pThunkHashTable;
    static BOOL s_fTPTableFieldsInitialized;
};

extern "C" UINT32 STDCALL TransparentProxyStubWorker(TransitionBlock * pTransitionBlock, TADDR pMethodDescOrSlot);

// Holder for remoting profiler notifications
class ProfilerRemotingClientCallbackHolder
{
public:
    ProfilerRemotingClientCallbackHolder();
    ~ProfilerRemotingClientCallbackHolder();
};

// These stub manager classes help the debugger to step
// through the various stubs and thunks generated by the
// remoting infrastructure
class CVirtualThunkMgr :public StubManager
{
    friend class CTPMethodTable;

    VPTR_VTABLE_CLASS(CVirtualThunkMgr, StubManager)

public:
    static void InitVirtualThunkManager();
#ifndef DACCESS_COMPILE
    CVirtualThunkMgr()
    {
        WRAPPER_NO_CONTRACT;
    }
#endif

public:
#ifdef _DEBUG
    virtual const char * DbgGetName() { LIMITED_METHOD_CONTRACT; return "CVirtualThunkMgr"; }
#endif

    virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress);

    virtual BOOL DoTraceStub(PCODE stubStartAddress, TraceDestination *trace) DAC_EMPTY_RET(FALSE);

    static MethodDesc *Entry2MethodDesc(PCODE StubStartAddress, MethodTable *pMT);

private:
    // Private methods
    LPBYTE FindThunk(const BYTE *stubStartAddress);
    static MethodDesc *GetMethodDescByASM(PCODE startaddr, MethodTable *pMT);
    static BOOL IsThunkByASM(PCODE startaddr);

    // Private statics
    static CVirtualThunkMgr *s_pVirtualThunkMgr;

#ifdef DACCESS_COMPILE
protected:
    virtual LPCWSTR GetStubManagerName(PCODE addr)
        { LIMITED_METHOD_CONTRACT; return W("CVirtualThunk"); }
#endif
};


#ifndef HAS_REMOTING_PRECODE

class CNonVirtualThunkMgr :public StubManager
{
    friend class CTPMethodTable;

    VPTR_VTABLE_CLASS(CNonVirtualThunkMgr, StubManager)
    
public:
    static void InitNonVirtualThunkManager();

public:
#ifdef _DEBUG
    virtual const char * DbgGetName() { return "CNonVirtualThunkMgr"; }
#endif

    virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress);

    virtual BOOL DoTraceStub(PCODE stubStartAddress, TraceDestination *trace) DAC_EMPTY_RET(FALSE);

    virtual BOOL TraceManager(Thread *thread,
                              TraceDestination *trace,
                              CONTEXT *pContext,
                              BYTE **pRetAddr) DAC_EMPTY_RET(FALSE);

    static MethodDesc *Entry2MethodDesc(PCODE StubStartAddress, MethodTable *pMT);

private:
    // Private methods
    CNonVirtualThunk* FindThunk(const BYTE *stubStartAddress);
    static MethodDesc *GetMethodDescByASM(PCODE startaddr);
    static BOOL IsThunkByASM(PCODE startaddr);

    // Private statics
    static CNonVirtualThunkMgr *s_pNonVirtualThunkMgr;

#ifdef DACCESS_COMPILE
protected:
    virtual LPCWSTR GetStubManagerName(PCODE addr)
        { LIMITED_METHOD_CONTRACT; return W("CNonVirtualThunk"); }
#endif
};

#endif // HAS_REMOTING_PRECODE

#endif // __REMOTING_H__
